#include "dispatch.h"
#include "sys/socket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "proxy.h"
#include "errno.h"

int new_socket(){

	int sfd;
	int flags;

	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		return -1;
	}

	if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
			fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
		perror("setting O_NONBLOCK");
		close(sfd);
		return -1;
	}
	return sfd;
}

int listen_socket(int sfd, short port){

	sockaddr_in addr;
	socklen_t addrlen;

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);

	//struct in_addr sinaddr;
	//inet_pton(AF_INET, INADDR_ANY, &sinaddr);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);//sinaddr.s_addr;
	
	//int ret = inet_pton(AF_INET, INADDR_ANY, &addr);

	int ret = bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
	if( ret < 0 ){
		return ret;
	}

	::listen(sfd, 1024);
	if( ret < 0 ){
		return -10+ret;
	}
	return 0;
}

int accept_socket(int sfd){

	printf("a new connect in\n");
	sockaddr_in addr;
	socklen_t addrlen;
	int clientFD;
	if ((clientFD = accept(sfd, (struct sockaddr *)&addr, &addrlen)) == -1) {
		if (errno == EAGAIN || errno == EWOULDBLOCK) {
		} else if (errno == EMFILE) {
		} else {
			perror("accept()");
		}
		return -1;
	}
	int flags ;
	if ((flags = fcntl(clientFD, F_GETFL, 0)) < 0 ||
			fcntl(clientFD, F_SETFL, flags | O_NONBLOCK) < 0) {
		perror("setting O_NONBLOCK");
		close(clientFD);
		return -2;
	}
	return clientFD;
	//dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST,
	//                         DATA_BUFFER_SIZE, tcp_transport);
}

int connect_socket(int sfd, const string&ip, int port){

	struct sockaddr_in addr;

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip.c_str());

	int ret = connect(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
	if( ret < 0 && errno != EINPROGRESS ){
		printf("errno:%d\n", errno);
		return -1;
	}
	return 0;

}


void drive_machine(int sfd, short int eventType, void *args){

	conn *c = (conn *)args;
	bool stop = false;
	while(!stop){
		switch(c->status){
			case C_LISTEN:
			{	
				int fd = accept_socket(sfd);
				printf("new fd:%d\n", fd);
				struct conn *pConn = conn_new(fd, C_READ, EV_READ | EV_PERSIST, 1024);
				if( pConn == NULL ){
					c->status = C_ERROR;
				}
				stop = true;
				break;
			}
			case C_READ:
				conn_read( c );
				break;
			case C_PARSE:
				if( c->p_backConn != NULL ){
					c->status = C_PROXY;
					break;
				}
				proxy_parse( c );
				c->status = C_READ;
				stop = true;
				break;
			case C_PROXY:
				proxy_data( c );
				stop = true;
				break;
			case C_FIN:
				printf("a connect is close fd:%d\n", c->sfd);
				conn_delete( c );
				stop = true;
				break;
			case C_ERROR:
				break;
		}
	}
}

